import os
import subprocess
import time

'''
************************************************************
        运行后，窗口会持续存在，如果窗口被关闭了，那么nginx的服务将会随之关闭
        只要这两个实例的nginx_path相同
        那么实例一个NginxManger并启动后，在这个实例的运行窗口没有被关闭的情况下
        在实例一个NginxManger可以关闭nginx服务，原先的运行窗口也会随之关闭
        如：
            在test_1.py 运行NginxManger(nginx_path='aaa').Run_nginx()
            在test_2/py 运行NginxManger(nginx_path='aaa').Stop_nginx()是可以关闭nginx的
************************************************************
'''


class NginxManger:

    def __init__(self, nginx_path):

        self.nginx_path = os.path.abspath(nginx_path)
        print(f"Nginx路径: {self.nginx_path}")

        self.config_path = os.path.join(self.nginx_path, 'conf', 'nginx.conf')
        os.makedirs(os.path.dirname(self.config_path), exist_ok=True)

        self.listen_port = None
        self.server_name = None
        self.location = []
        self.tem_content = '          proxy_set_header Cookie $http_cookie;\n' \
                         '            proxy_set_header Host $host;\n' \
                         '            proxy_set_header X-Real-IP $remote_addr;\n' \
                         '            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n' \
                         '            proxy_set_header X-Forwarded-Proto $scheme;'
        
        self.Server_List = []
        self.App_List = []
        self.processes = []

    def Set_Listening(self, listen_dict):
        self.listen_port = listen_dict.get('listen_port')
        self.server_name = listen_dict.get('server_name')

        if listen_dict.get('ssl_certificate') and listen_dict.get('ssl_certificate_key'):
            self.ssl_certificate = listen_dict.get('ssl_certificate').replace('\\', '/')
            self.ssl_certificate_key = listen_dict.get('ssl_certificate_key').replace('\\', '/')
            self.listen_port += ' ssl'
        else:
            self.ssl_certificate = None
            self.ssl_certificate_key = None

    def Set_Mapping(self, path, urls, app_path=None):

        if not isinstance(urls, list):
            raise TypeError("urls必须是一个列表")
        
        for url in urls:
            self.location.append(
                f"        location {url} {{\n"
                f"            proxy_pass {path};\n"
                f"  {self.tem_content}\n        }}\n\n"
            )
        
        if app_path and app_path not in self.App_List:
            self.App_List.append(app_path)

    def Set_One_Server(self):
        self.one_server_config = '    server {\n'

        self.one_server_config += f"        listen {self.listen_port};\n" \
                                f"        server_name {self.server_name};\n\n"
        
        if self.ssl_certificate and self.ssl_certificate_key:
            self.one_server_config += f"        ssl_certificate {self.ssl_certificate};\n"
            self.one_server_config += f"        ssl_certificate_key {self.ssl_certificate_key};\n\n"

        for location in self.location:
            self.one_server_config += location

        self.one_server_config += f"        error_page 500 502 503 504  /50x.html;\n"
        self.one_server_config += f"        location = /50x.html {{root html;}}\n    }}\n\n"

        self.Server_List.append(self.one_server_config)
        self.location = []

    def Save_Conf(self):
        try:
            con_str = f"worker_processes auto;\n\n" \
                    f"events {{\n" \
                    f"    worker_connections 512;\n" \
                    f"}}\n\n"

            con_str += f"http {{\n" \
                     f"    error_log logs/error.log;\n" \
                     f"    access_log logs/access.log;\n\n"
            
            for server in self.Server_List:
                con_str += server

            con_str += "}\n"

            with open(self.config_path, 'w') as f:
                f.write(con_str)

            print(f"配置文件已保存到: {self.config_path}")
            return True
        
        except Exception as e:
            print(f"保存配置文件时出错: {str(e)}")
            return False

    def Run_nginx(self):
        try:
            # 先尝试停止可能存在的 Nginx 进程
            self.Stop_nginx()

            self.Run_App_List()
            
            # 等待一小段时间确保之前的进程完全停止
            time.sleep(1)

            process = subprocess.Popen(
                [os.path.join(self.nginx_path, 'nginx.exe'), '-c', 'conf/nginx.conf'], 
                stdout=subprocess.PIPE, 
                stderr=subprocess.PIPE, 
                text=True,
                cwd=self.nginx_path)
            
            stdout, stderr = process.communicate()
            
            if stderr:
                print(f"Nginx启动错误: {stderr}")
                return False
                
            print("Nginx服务已启动")
            return True
        
        except Exception as e:
            print(f"启动Nginx时发生错误: {str(e)}")
            return False

    def Stop_nginx(self):
        try:
            # 检查 Nginx 进程是否存在
            nginx_running = False
            
            # 使用 tasklist 命令检查 nginx.exe 是否在运行
            process = subprocess.Popen(
                ['tasklist', '/FI', 'IMAGENAME eq nginx.exe', '/NH'],
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
                text=True
            )
            stdout, stderr = process.communicate()
            
            if 'nginx.exe' in stdout:
                nginx_running = True
            
            # 如果 Nginx 不在运行，直接返回成功
            if not nginx_running:
                print("Nginx 服务未运行，无需停止")
                return True
            
            # Nginx 正在运行，尝试停止它
            process = subprocess.Popen(
                [os.path.join(self.nginx_path, 'nginx.exe'), '-s', 'quit'],
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
                text=True,
                cwd=self.nginx_path
            )
            stdout, stderr = process.communicate()
            
            if stderr:
                print(f"停止Nginx时出错: {stderr}")
                # 尽管有错误，我们仍然返回 True，因为可能是 Nginx 已经不在运行
                return True
                
            print("Nginx服务已停止")
            return True
        except Exception as e:
            print(f"停止Nginx时发生错误: {str(e)}")
            # 同样，我们返回 True，因为错误可能是由于 Nginx 不在运行
            return True

    def Run_App(self, app_path):
        try:
            if not os.path.exists(app_path):
                print(f"错误: 应用脚本不存在: {app_path}")
                return False
            
            # 获取脚本目录和文件名
            script_dir = os.path.dirname(app_path)
            script_name = os.path.basename(app_path)
            
            # 构建命令 - 在新的CMD窗口中运行Python脚本
            cmd_command = f'start cmd /k "cd /d "{script_dir}" && python {script_name}"'
            
            # 执行命令
            process = subprocess.Popen(cmd_command, shell=True)
            
            # 记录进程ID
            self.processes.append(process)
            print(f"已在新CMD窗口中启动应用: {app_path}")
            return True
            
        except Exception as e:
            print(f"启动应用 {app_path} 时出错: {str(e)}")
            return False

    def Run_App_List(self):
        """启动 App_List 中的所有 Python 脚本"""
        success = True
        for app_path in self.App_List:
            if not self.Run_App(app_path):
                success = False
        return success

if __name__ == '__main__':
    pass
    # nginx_path 使用绝对路径 或 确保相对路径正确
    # NM = NginxManger(nginx_path='nginx1272')
    #
    #
    # NM.Set_Listening({'listen_port': '15000',
    #                  'server_name': '127.0.0.1',})
    #
    # NM.Set_Mapping('http://192.168.10.10:6020', ['/aiphoto', '/'])
    #
    # NM.Set_One_Server()
    #
    # NM.Save_Conf()
    # NM.Run_nginx()

